//BT
#include "BluetoothSerial.h"
#if !defined(CONFIG_BT_ENABLED) || !defined(CONFIG_BLUEDROID_ENABLED)
#error Bluetooth is not enabled! Please run `make menuconfig` to and enable it
#endif
BluetoothSerial SerialBT;

//oled
#include <Wire.h>
#include "SSD1306.h"
SSD1306  display(0x3c, 21, 22);

#include "String.h"

// pitches.h
#define NOTE_D0 -1
#define NOTE_D1 294
#define NOTE_D2 330
#define NOTE_D3 350
#define NOTE_D4 393
#define NOTE_D5 441
#define NOTE_D6 495
#define NOTE_D7 556

#define NOTE_DL1 147
#define NOTE_DL2 165
#define NOTE_DL3 175
#define NOTE_DL4 196
#define NOTE_DL5 221
#define NOTE_DL6 248
#define NOTE_DL7 278

#define NOTE_DH1 589
#define NOTE_DH2 661
#define NOTE_DH3 700
#define NOTE_DH4 786
#define NOTE_DH5 882
#define NOTE_DH6 990
#define NOTE_DH7 112

//yibu
long int Yibu_music =150 ;
long int Yibu_Main = 120;
long int Yibu_lamp = 180;
long int Yibu_BT = 1000;

//music
//huluwa
int Tones_1[] = {NOTE_DH1, NOTE_D6, NOTE_D5, NOTE_D6, NOTE_D0,
  NOTE_DH1, NOTE_D6, NOTE_D5, NOTE_DH1, NOTE_D6, NOTE_D0, NOTE_D6,
  NOTE_D6,  NOTE_D5, NOTE_D6, NOTE_D0, NOTE_D6,
  NOTE_DH1, NOTE_D6, NOTE_D5, NOTE_DH1, NOTE_D6, NOTE_D0};  
float Tonestime_1[]={
  1, 1, 0.5, 0.5, 1,
  0.5, 0.5, 0.5, 0.5, 1, 0.5, 0.5,
  1, 1, 1, 1, 0.5, 0.5,
  0.5, 0.5, 0.5, 0.5 };
//    400*Tonestime_1
//Mario
int Tones_2[] = {330, 330, 330, 262, 330, 392, 196, 262, 196, 165, 
220, 247, 233, 220, 196, 330, 392, 440, 349, 392, 330, 262, 294,
247, 262, 196, 165, 220, 247, 233, 220, 196, 330, 392,440, 349, 392, 330, 262, 294, 
247, 392, 370, 330, 311, 330, 208, 220, 262, 220, 262,
294, 392, 370, 330, 311, 330, 523, 523, 523, 392, 370,
330, 311, 330, 208, 220, 262,220, 262, 294, 311, 294, 262, 262, 262,
262, 262, 294, 330, 262, 220, 196, 262, 262,262, 262, 294, 330, 262, 
262, 262, 262, 294, 330, 262, 220, 196};
int Tonestime_2[] = {8,4,4,8,4,2,2,3,3,3,4,4,8,4,8,8,8,4,8,4,3,8,8,3,3,3
,3,4,4,8,4,8,8,8,4,8,4,3,8,8,2,8,8,8,4,4,8,8,4,8,8,3,8,8,
8,4,4,4,8,2,8,8,8,4,4,8,8,4,8,8,3,3,3,1,8,4
,4,8,4,8,4,8,2,8,4,4,8,4,1,8,4,4,8,4,8,4,8,2};
//      800/Tonestime_2
const int LEDC_TIMER_12_BIT = 12;
int Music_Xu = 0; //Music_i
int Qi_Diao_1 = 1; //major tone
int Qi_Diao_2 = 2;//major tone
int YIN_Lian = 250;//0-250 //volume

//BT
int  GetFrom_xiawei()
{
  ;
}
int  GetFrom_shangwei()// Input the required mode from the upper computer
{
  
  if(SerialBT.available())
  {

   char i = SerialBT.read();
   if(isDigit(i))
   {
    return i-48;//char to int    
   }
  }else{
    return 0;
  }
  
}
int PrintfTo_xiawei()
{
  ;
}
int PrintfTo_shangwei(String ms)// Send string to upper computer
{
  unsigned int msl = ms.length();
  for(int i = 0 ; i != msl ; i++)
  {
    SerialBT.write(ms[i]);
  }
  return 1;
}

//PIN
const int TankLevel = 36;//Potentiometer
const int ValveOpening = 25;//LED red
const int LevelHigh    = 26;//LED green
const int LevelLow     = 27;//LED blue
const int SystemHold = 15;//Push-button
const int Buzzer = 14;//Buzzer

//duty cycle
const int freq = 500;
const int resolution = 8;

//PWMChannel
const int ValveOpening_PWMChannel = 0;
const int LevelHigh_PWMChannel = 2;
const int LevelLow_PWMChannel = 4;
const int Buzzer_PWMChannel = 6;

//tank_state
int TankState = 1;  // state of reservoir
int TankState_Last = 0;  //Last state of reservoir
int TankState_Low = 0;//Low state of reservoir
int TankState_Nomo = 1;//noromal state of reservoir
int TankState_High = 2;//high state of reservoir
int TankState_Hold = 3;//hold state of reservoir
//Hold state
int SystemHold_state = 0;// 0 is off
const int Hold_close_state = 1;
const int Hold_open_state = 0;
//BT BlueTooth set state'
int BT_push = 2;
int BT_pull = 3;
int BT_state = 3;//hold set off
int BT_state_now = 3;//hold set

//Led
int Led_light = 250; //initial Led light
int Led_xu = 0;//led_i

//bt-set
int bt_set = 1;//not pull button

int HULUWA(void)//initial music play
{
   Yibu_music = millis();
   Music_Xu = 0 ;
   return 1;
}
int TankLevel_5(void)//return TankLevel from read 5 time average value
{
  int TankLevel_Value = 0;  
  int TankLevel_M100_Value = 0;// change 4095 to 100
  int Total_5_Value = 0;
  for(int i = 0 ; i!=5;i++)
  {
    TankLevel_Value = analogRead(TankLevel); // read TankLevel_Value value 
    TankLevel_M100_Value = map(TankLevel_Value, 0, 4095, 0, 100);// change 4095 to 100
    Total_5_Value += TankLevel_M100_Value;
  }
  return Total_5_Value/5;
}
int StarPrint(int num)//print the Image of reservoir proportion
{
  printf("************\n");//Lid
  printf("*");//left
  for(int i = num/10;i!= 0 ;i--)//Middle
  {
    printf("#");
  }
  
  for(int i = 10 - num/10;i!= 0 ;i--)//Free
  {
    printf(" ");
  }
  printf("*");//Right
  printf("\n");
  printf("************\n");//Foundation
  return 1;
}

void setup() {
  // put your setup code here, to run once:
  display.init();
  Serial.begin(115200);
  //ledcSetup(Buzzer_PWMChannel,Tones_1[Music_Xu]*Qi_Diao, LEDC_TIMER_12_BIT);
  //ledcAttachPin(Buzzer,Buzzer_PWMChannel);
    //LED PIN OUTPUT SET
  pinMode(ValveOpening,OUTPUT);
  pinMode(LevelHigh,OUTPUT);
  pinMode(LevelLow,OUTPUT);
  
  //BUTTON PIN INPUT_PULLUP SET
  pinMode(SystemHold,INPUT_PULLUP);

    //ValveOpening PWN MODE
  ledcSetup(ValveOpening_PWMChannel,freq,resolution);
  ledcSetup(LevelHigh,freq,resolution);
  ledcSetup(LevelLow,freq,resolution);
  
  ledcAttachPin(ValveOpening,ValveOpening_PWMChannel);
  ledcAttachPin(LevelHigh,LevelHigh_PWMChannel);
  ledcAttachPin(LevelLow,LevelLow_PWMChannel);
  
  //BT
  SerialBT.begin("ESP32test2"); //Bluetooth device name
  Serial.println("The device started, now you can pair it with bluetooth!");
}

void loop() {
  // put your main code here, to run repeatedly:
  while(1){
    //Serial.println("star");
    //Serial.println(millis());

//music huluwa
if(millis() >  Yibu_music)
{
  if(( (TankState== TankState_Low)||(TankState== TankState_High)))
  {
  //Serial.println("star 2");
  Yibu_music += Tonestime_1[Music_Xu]*400;
  //pwn tones[i];
  ledcSetup(Buzzer_PWMChannel,Tones_1[Music_Xu]*Qi_Diao_1, LEDC_TIMER_12_BIT);
  ledcAttachPin(Buzzer,Buzzer_PWMChannel);
  ledcWrite(Buzzer_PWMChannel, YIN_Lian);
  //ledcSetup(6,330, 12);
  //ledcAttachPin(14,6);
  //ledcWrite(6, 250);
  
  
  Music_Xu++;
  //Serial.println(Music_Xu);
  if(Music_Xu>(sizeof(Tones_1)/sizeof(Tones_1[0])))
  Music_Xu = 0;
  }
}
// music maliao
if((millis() >  Yibu_music))
{
  if( (TankState== TankState_Hold))
  {
  //Serial.println("star 6");
  Yibu_music += 800/Tonestime_2[Music_Xu];
  //pwn tones[i];
  ledcSetup(Buzzer_PWMChannel,Tones_2[Music_Xu]*Qi_Diao_2, LEDC_TIMER_12_BIT);
  ledcAttachPin(Buzzer,Buzzer_PWMChannel);
  ledcWrite(Buzzer_PWMChannel, YIN_Lian);
  //ledcSetup(6,330, 12);
  //ledcAttachPin(14,6);
  //ledcWrite(6, 250);
  
  
  Music_Xu++;
  //Serial.println(Music_Xu);
  if(Music_Xu>(sizeof(Tones_1)/sizeof(Tones_1[0])))
  Music_Xu = 0;
  }
}
//close music
if((TankState== TankState_Nomo))
{
  ledcWrite(Buzzer_PWMChannel, 0);
  //Serial.println("star 2.5");
}



//Serial.println("star 1.5");
//yibu main
if(millis()> Yibu_Main)
{
  Yibu_Main +=120;
  //music play check
  if(TankState_Last== TankState_Nomo)//check the state,If the last is not normal mode
  {
    if(TankState==TankState_Low||TankState==TankState_High||TankState==TankState_Hold)
    {
    HULUWA();//start playing music of all
    TankState_Last = TankState ;
    }
  }

  int holding = digitalRead(SystemHold);//Get key information of physical machine
  BT_state =  BT_state_now;//Get key information of upper pc machine
  if(holding)//0 is off of  physical machine
  {
    //Serial.println("bbbbbbbbbbbbbbbbbbbbbb");
    if(BT_state == BT_push)//2 == long time
    {
      
      SystemHold_state = Hold_open_state;   
      //Hold_open_state
    }
    if(BT_state == BT_pull)//3 == close time
    {
      SystemHold_state =Hold_close_state;
      
    }
  }else{
    //Serial.println("aaaaaaaaaaaaaaaaaaaaaaaaaa");
    SystemHold_state = Hold_open_state;
  }
  //Serial.println(BT_state);
  if(!SystemHold_state)//if open the value
  {
    int TankLevel_M100_Value = TankLevel_5();//return TankLevel
    //Serial.println("star5");
    TankState_Last = TankState;//set state
    TankState =TankState_Hold;
    ledcWrite(ValveOpening_PWMChannel,0);//close red led
    //senior printf
    Serial.printf("senior read :%d\n",(int)(4095*(double)((double)TankLevel_M100_Value/100)));
    Serial.println("Open Valve - System Hold");
    Serial.printf("%d%%\n",TankLevel_M100_Value);
    StarPrint(TankLevel_M100_Value);//printf the picture
    Serial.printf("Duty Cycle: 0\n");
    //oled
    display.clear();
    display.setFont(ArialMT_Plain_16);
    display.drawString(0,0, "TankLevel :" + String(TankLevel_M100_Value) +"%");
    display.setFont(ArialMT_Plain_24);
    display.drawString(0,16, "Holding");
    display.display();
    
    
    
  }else//if don't open the value
  {
    
     int TankLevel_M100_Value = TankLevel_5();//return TankLevel
     //Serial.println(TankLevel_M100_Value);
     if(TankLevel_M100_Value < 30)//<30%
    {
      TankState_Last = TankState;//set state
      TankState = TankState_Low;
      ledcWrite(LevelHigh_PWMChannel,0);//close the high led
      ledcWrite(ValveOpening_PWMChannel,200);//open red led
      //senior print
      Serial.printf("senior read :%d\n",(int)(4095*(double)((double)TankLevel_M100_Value/100)));
      Serial.println("Tank Level Low");
      Serial.printf("%d%%\n",TankLevel_M100_Value);
      StarPrint(TankLevel_M100_Value);//printf the picture
      Serial.printf("Duty Cycle: 200\n");
      //oled
      display.clear();
      display.setFont(ArialMT_Plain_16);
      display.drawString(0,0, "TankLevel :" + String(TankLevel_M100_Value) +"%");
      display.setFont(ArialMT_Plain_24);
      display.drawString(0,16, "Low");
      display.display();
      
      
    }else if((TankLevel_M100_Value > 30)&&(TankLevel_M100_Value < 85))// nomal
    {
      TankState_Last = TankState;//set state
      TankState = TankState_Nomo;
      ledcWrite(ValveOpening_PWMChannel,255*(double)((double)TankLevel_M100_Value/100));//open red led
      //Serial.println(255*(double)((double)TankLevel_M100_Value/100));
      //ledcWrite(ValveOpening_PWMChannel,36);//红灯亮
      ledcWrite(LevelHigh_PWMChannel,0);///close the high led
      ledcWrite(LevelLow_PWMChannel,0);//close the low led
      //Serial.println(255*(((double)TankLevel_M100_Value/100)));
      //senior print
      Serial.printf("senior read :%d\n",(int)(4095*(double)((double)TankLevel_M100_Value/100)));
      Serial.println("Tank Level Normal");
      Serial.printf("%d%%\n",TankLevel_M100_Value);
      StarPrint(TankLevel_M100_Value);//printf the picture
      Serial.printf("Duty Cycle: %d\n",(int)(255*((double)TankLevel_M100_Value/100)));
      //oled
      display.clear();
      display.setFont(ArialMT_Plain_16);
      display.drawString(0,0, "TankLevel :" + String(TankLevel_M100_Value) +"%");
      display.setFont(ArialMT_Plain_24);
      display.drawString(0,16, "Normal");
      display.display();
      
    }else if(TankLevel_M100_Value >= 85)
    {
      TankState_Last = TankState; //set state
      TankState = TankState_High;
      ledcWrite(LevelLow_PWMChannel,0);//close low led
      ledcWrite(ValveOpening_PWMChannel,10);//open red led
      //senior print
      Serial.printf("senior read :%d\n",(int)(4095*(double)((double)TankLevel_M100_Value/100)));
      Serial.println("Tank Level Nearly Full");
      Serial.printf("%d%%\n",TankLevel_M100_Value);
      StarPrint(TankLevel_M100_Value);//printf the picture
      Serial.printf("Duty Cycle: 10\n");
      //oled
      display.clear();
      display.setFont(ArialMT_Plain_16);
      display.drawString(0,0, "TankLevel :" + String(TankLevel_M100_Value) +"%");
      display.setFont(ArialMT_Plain_24);
      display.drawString(0,16, "Nearly Full");
      display.display();
      
    }
    //Serial.println("TankState:");
    //Serial.println(TankState);
    //Serial.println("TankState_Last:");
    //Serial.println(TankState_Last);
    //delay(100);
  }
  
  
}
//lamp
    if(millis()> Yibu_lamp)
    {
      //Serial.println("led");
      Yibu_lamp+=8;
      if(TankState == TankState_Low)//low level
      {
        
        ledcWrite(LevelLow_PWMChannel,Led_light);// open low led
        if(Led_xu == 0)
        {
        Led_light--;
        }else{
        Led_light++;
        }
      }
      if(TankState == TankState_Nomo)//noromal led
      {
        ledcWrite(LevelHigh_PWMChannel,0);//close green led
        ledcWrite(LevelLow_PWMChannel,0);//close blue led
        //Serial.println("led 2");
        
      }
      if(TankState == TankState_High)//high led
      {
        
        ledcWrite(LevelHigh_PWMChannel,Led_light);// open high led
        //Serial.println(Led_light);
        if(Led_xu == 0)
        {
        Led_light-=2;
        }else{
        Led_light+=2;
        }
      }
      if(TankState == TankState_Hold)//hold led
      {
        ledcWrite(LevelLow_PWMChannel,Led_light); //open low led
        ledcWrite(LevelHigh_PWMChannel,Led_light);//open high led
        if(Led_xu == 0)
        {
        Led_light--;
        }else{
        Led_light++;
        }
      }
      if(Led_light <= 50&&Led_xu == 0)//Gradual darker
      {
        //Led_light = 250;
        Led_xu = 1;
      }
      if(Led_light >= 250&&Led_xu == 1)//Gradual lighter
      {
        //Led_light = 250;
        Led_xu = 0;
      }
    }
  
  if(millis()> Yibu_BT)
  {
    //upper pc print from bt
    PrintfTo_shangwei("Please enter the required mode");
    PrintfTo_shangwei("\n");
    PrintfTo_shangwei("1: test switch ");
    PrintfTo_shangwei("\n");
    PrintfTo_shangwei("2: long open switch ");
    PrintfTo_shangwei("\n");
    PrintfTo_shangwei("3: long close switch");
    PrintfTo_shangwei("\n");
    int BT_state_get = GetFrom_shangwei();
    if(BT_state_get == 1)
    {
      PrintfTo_shangwei("-------------Normal communication-------------");
      PrintfTo_shangwei("\n");
    }
    if(BT_state_get == BT_push||BT_state_get == BT_pull)// check Correct inputs
    {
      BT_state_now = BT_state_get;
    }
    
    PrintfTo_shangwei("state :");
    PrintfTo_shangwei(String(BT_state));
    PrintfTo_shangwei("\n");
    if(TankState == TankState_Hold||BT_state == BT_push)
    {
      PrintfTo_shangwei("TankLevel :");
      PrintfTo_shangwei("Holding");
      PrintfTo_shangwei("\n");
    }
    if(TankState == TankState_Low)
    {
      PrintfTo_shangwei("TankLevel :");
      PrintfTo_shangwei("Low");
      PrintfTo_shangwei("\n");
    }
    if(TankState == TankState_Nomo)
    {
      PrintfTo_shangwei("TankLevel :" );
      PrintfTo_shangwei("Normal");
      PrintfTo_shangwei("\n");
    }
    if(TankState == TankState_High)
    {
      
      PrintfTo_shangwei("TankLevel :");
      PrintfTo_shangwei("Nearly Full");
      PrintfTo_shangwei("\n");
    }
    Yibu_BT +=1000;
  }

 }


}


























//基于cpu计时的millis()做成的异步并发多线程

/*
 * 402
Users/ficeto/Desktop/ESP32/ESP32/esp-idf-public/components/freertos/queue.c:1442 (xQueueGenericReceive)- assert failed!
abort() was called at PC 0x40088091 on core 1
Backtrace: 0x4008b764:0x3ffb1ef0 0x4008b991:0x3ffb1f10 0x40088091:0x3ffb1f30 0x400d1747:0x3ffb1f70 0x400d0c41:0x3ffb1f90 0x400d20ed:0x3ffb1fb0 0x4008a2b1:0x3ffb1fd0
 */
//问题在于 ledcwrite(0,0)放在循环最前面，已经解决

//esp32不支持analogwrite()
//PWMChannel有上限数量 已知不能超过16
//感觉搞个异步或者多线程，否则呼吸灯不能和蜂鸣器一起
//esp32 不支持scoop
/*
16 channels LEDC which is PWM
8 channels SigmaDelta which uses SigmaDelta modulation
2 channels DAC which gives real analog output
 */
